home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 27 / CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso / CUCD / Magazine / C_Tutorial / Part-15 / hook2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-04  |  11.0 KB  |  441 lines

  1. #include<dos/dos.h>
  2. #include<dos/exall.h>
  3. #include<exec/libraries.h>
  4. #include<exec/memory.h>
  5. #include<exec/nodes.h>
  6. #include<graphics/text.h>
  7. #include<intuition/intuition.h>
  8. #include<intuition/screens.h>
  9. #include<libraries/gadtools.h>
  10. #include<utility/tagitem.h>
  11.  
  12. #include<string.h>
  13. #include<stdio.h>
  14. #include<stdlib.h>
  15.  
  16. #include<clib/alib_protos.h>
  17. #include<clib/dos_protos.h>
  18. #include<clib/exec_protos.h>
  19. #include<clib/gadtools_protos.h>
  20. #include<clib/graphics_protos.h>
  21. #include<clib/intuition_protos.h>
  22.  
  23. /* The library base global variables */
  24. struct Library* DosBase;
  25. struct Library* GadToolsBase;
  26. struct Library* GfxBase;
  27. struct Library* IntuitionBase;
  28.  
  29. /* Need to give prototypes for our functions */
  30. void handleIDCMP(struct Window*);
  31. void setupWindow(void);
  32. void createWindow(struct Gadget*);
  33.  
  34. void addNode(char*,int);
  35. void freeNode(struct Node*);
  36. void freeList(void);
  37. int  fillList(char*);
  38. void sortList(void);
  39.  
  40. #define MYFONTSIZE        (8)
  41.  
  42. /* Some constants for the size of the window */
  43. #define MYWIN_WIDTH        (200)
  44. #define MYWIN_HEIGHT    (200)
  45.  
  46. /* Some constants for the position and size of our gadget */
  47. #define MYGAD_LEFT        (10)
  48. #define MYGAD_TOP            (10+MYFONTSIZE)
  49. #define MYGAD_WIDTH        (MYWIN_WIDTH-MYGAD_LEFT*2)
  50. #define MYGAD_HEIGHT    (MYWIN_HEIGHT-MYGAD_TOP*2+MYFONTSIZE)
  51. #define MYGAD_TEXT        ("Files")
  52. #define MYGAD_ID            (0)
  53.  
  54.  
  55. /* Constants for the Node type, deciding dir or file */
  56.  
  57. #define MY_FILE  (NT_USER)
  58. #define MY_DIR   (NT_USER-1)
  59.  
  60.  
  61. /* Initialised structure declaration: describes standard Topaz font */
  62. static struct TextAttr topazFont = { "topaz.font", MYFONTSIZE, 0, 0, };
  63.  
  64. static struct List mylist;
  65. static int mycount = 0;
  66.  
  67. void addNode(char* name, int isdir)
  68. {
  69.     if(name)
  70.     {
  71.         struct Node* node = AllocVec(sizeof(struct Node), MEMF_PUBLIC | MEMF_CLEAR);
  72.         if(node)
  73.         {
  74.             if(node->ln_Name = AllocVec(strlen(name)+1, MEMF_PUBLIC))
  75.                 strcpy(node->ln_Name, name);
  76.             node->ln_Type = (isdir ? MY_DIR : MY_FILE);
  77.             AddTail(&mylist, node);
  78.             mycount++;
  79.         }
  80.     }
  81. }
  82.  
  83. void freeNode(struct Node* node)
  84. {
  85.     FreeVec(node->ln_Name);
  86.     FreeVec(node);
  87. }
  88.  
  89. void freeList()
  90. {
  91.     struct Node* work;
  92.     struct Node* next = mylist.lh_Head;
  93.     while(next->ln_Succ)
  94.     {
  95.         work = next;
  96.         next = next->ln_Succ;
  97.         freeNode(work);
  98.     }
  99.     mycount = 0;
  100. }
  101.  
  102. #define EABUFF_NUM  (30)
  103. #define EABUFF_SIZE (EABUFF_NUM*sizeof(struct ExAllData))
  104.  
  105. /* Our buffer for ExAll() */
  106. static struct ExAllData EABuff[EABUFF_NUM];
  107.  
  108. int fillList(char* dir)
  109. {
  110.     int success = FALSE;
  111.     /* Get a lock on the directory */
  112.     BPTR lock = Lock(dir, ACCESS_READ);
  113.     if(lock)
  114.     {
  115.         /* Allocate ExAll control object */
  116.         struct ExAllControl* eac = AllocDosObject(DOS_EXALLCONTROL,NULL);
  117.         if(eac)
  118.         {
  119.             int going = TRUE;
  120.             /* Must initialise LastKey to zero before calling ExAll() */
  121.             eac->eac_LastKey = 0;
  122.             /* If we got this far we're OK */
  123.             success = TRUE;
  124.             while(going)
  125.             {
  126.                 /* Fill the buffer with directory entries */
  127.                 /* (We need the type as well as the name, so ED_TYPE) */
  128.                 going = ExAll(lock, EABuff, EABUFF_SIZE, ED_TYPE, eac);
  129.                 /* It's only an error if ExAll() returns FALSE and IoErr() signals */
  130.                 /* something other than running out of directory entries */
  131.                 if(!going)
  132.                     success = (IoErr() == ERROR_NO_MORE_ENTRIES);
  133.                 if(success)
  134.                 {
  135.                     if(eac->eac_Entries != 0)
  136.                     {
  137.                         /* Run through a buffer load of entries */
  138.                         struct ExAllData* ead = EABuff;
  139.                         while(ead)
  140.                         {
  141.                             /* If ed_Type>0 then it's a directory */
  142.                             addNode(ead->ed_Name, ead->ed_Type > 0);
  143.                             ead = ead->ed_Next;
  144.                         }
  145.                     }
  146.                 }
  147.             }
  148.             /* Print an error report if necessary */
  149.             if(!success)
  150.                 PrintFault(IoErr(), "Error");
  151.             FreeDosObject(DOS_EXALLCONTROL,eac);
  152.         }
  153.         else
  154.             printf("Error: could not create ExAll control object\n");
  155.         UnLock(lock);
  156.     }
  157.     else
  158.         printf("Error: could not lock directory \"%s\"\n", dir);
  159.     return success;
  160. }
  161.  
  162. int compareNode(const void* a, const void* b)
  163. {
  164.     struct Node** na = (struct Node**)a;
  165.     struct Node** nb = (struct Node**)b;
  166.     int diff = (*na)->ln_Type - (*nb)->ln_Type;
  167.     if(diff)
  168.         return diff;
  169.     else
  170.         return stricmp((*na)->ln_Name, (*nb)->ln_Name);
  171. }
  172.  
  173. void sortList()
  174. {
  175.     if(mycount > 1)
  176.     {
  177.         struct Node** sortarray = malloc(mycount*sizeof(struct Node*));
  178.         if(sortarray)
  179.         {
  180.             /* Copy pointers to the nodes into the array, in order */
  181.             int i = 0;
  182.             struct Node* next = mylist.lh_Head;
  183.             while(next->ln_Succ)
  184.             {
  185.                 sortarray[i++] = next;
  186.                 next = next->ln_Succ;
  187.             }
  188.             /* Sort the array of pointers */
  189.             qsort(sortarray, mycount, sizeof(struct Node*), &compareNode);
  190.             /* Clear the list, then refill it */
  191.             NewList(&mylist);
  192.             for(i=0; i<mycount; i++)
  193.                 AddTail(&mylist, sortarray[i]);
  194.             free(sortarray);
  195.         }
  196.     }
  197. }
  198.  
  199. /* Erase any part of "oldExtent" which is not covered by "newExtent" */
  200. void FillOldExtent(struct RastPort* rp,
  201.                    struct Rectangle* oldExtent,
  202.                    struct Rectangle* newExtent)
  203. {
  204.     if(oldExtent->MinX < newExtent->MinX)
  205.         RectFill(rp,oldExtent->MinX,
  206.                          oldExtent->MinY,
  207.                          newExtent->MinX-1,
  208.                          oldExtent->MaxY);
  209.  
  210.     if(oldExtent->MaxX > newExtent->MaxX)
  211.         RectFill(rp,newExtent->MaxX+1,
  212.                          oldExtent->MinY,
  213.                          oldExtent->MaxX,
  214.                          oldExtent->MaxY);
  215.  
  216.     if(oldExtent->MaxY > newExtent->MaxY)
  217.         RectFill(rp,oldExtent->MinX,
  218.                          newExtent->MaxY+1,
  219.                          oldExtent->MaxX,
  220.                          oldExtent->MaxY);
  221.  
  222.     if(oldExtent->MinY < newExtent->MinY)
  223.         RectFill(rp,oldExtent->MinX,
  224.                          oldExtent->MinY,
  225.                          oldExtent->MaxX,
  226.                          newExtent->MinY-1);
  227. }
  228.  
  229. /* Our code which will draw each node in the ListView */
  230. static ULONG __saveds RenderHook(register __a1 struct LVDrawMsg* msg,
  231.                                                                  register __a2 struct Node* node)
  232. {
  233.     struct RastPort* rp;
  234.     UBYTE state;
  235.     struct TextExtent extent;
  236.     WORD x,y, slack;
  237.     ULONG fit, apen, bpen;
  238.     UWORD* pens;
  239.     STRPTR name;
  240.  
  241.     if (msg->lvdm_MethodID != LV_DRAW)
  242.         return LVCB_UNKNOWN;
  243.  
  244.     /* Extract the RastPort and Pen info from the message */
  245.     rp = msg->lvdm_RastPort;
  246.     pens = msg->lvdm_DrawInfo->dri_Pens;
  247.  
  248.     /* Setup the fore- and back-ground colours   */
  249.     /* according to whether the item is selected */
  250.     state = msg->lvdm_State;
  251.     if(state == LVR_NORMAL)
  252.   {
  253.         apen = pens[node->ln_Type == MY_DIR ? HIGHLIGHTTEXTPEN : TEXTPEN];
  254.         bpen = pens[BACKGROUNDPEN];
  255.     }
  256.     else
  257.     {
  258.         apen = pens[node->ln_Type == MY_DIR ? BACKGROUNDPEN : FILLTEXTPEN];
  259.         bpen = pens[FILLPEN];
  260.     }
  261.     SetABPenDrMd(rp,apen,bpen,JAM2);
  262.  
  263.     name = node->ln_Name;
  264.  
  265.     /* Calculate how much of the name will fit, and how big it is */
  266.     fit = TextFit(rp,name,strlen(name),&extent,NULL,1,
  267.                                 msg->lvdm_Bounds.MaxX-msg->lvdm_Bounds.MinX-3,
  268.                                 msg->lvdm_Bounds.MaxY-msg->lvdm_Bounds.MinY+1);
  269.  
  270.     /* How much taller is the target area? */
  271.     slack = (msg->lvdm_Bounds.MaxY - msg->lvdm_Bounds.MinY) -
  272.               (extent.te_Extent.MaxY - extent.te_Extent.MinY);
  273.  
  274.     /* Put the name flush left and vertically centred */
  275.     x = msg->lvdm_Bounds.MinX - extent.te_Extent.MinX + 2;
  276.     y = msg->lvdm_Bounds.MinY - extent.te_Extent.MinY + ((slack+1) / 2);
  277.  
  278.     /* Draw the item */
  279.     Move(rp,x,y);
  280.     Text(rp,name,fit);
  281.  
  282.     /* Draw the blank part of the target area, too */
  283.     extent.te_Extent.MinX += x;
  284.     extent.te_Extent.MaxX += x;
  285.     extent.te_Extent.MinY += y;
  286.     extent.te_Extent.MaxY += y;
  287.  
  288.     SetAPen(rp,bpen);
  289.     FillOldExtent(rp,&msg->lvdm_Bounds,&extent.te_Extent);
  290.  
  291.     return LVCB_OK;
  292. }
  293.  
  294. /* The start of the program */
  295. void main()
  296. {
  297.     /* Open libraries... */
  298.     if(IntuitionBase = OpenLibrary("intuition.library",37))
  299.     {
  300.         if(GadToolsBase = OpenLibrary("gadtools.library",37))
  301.         {
  302.             if(DosBase = OpenLibrary("dos.library",37))
  303.             {
  304.                 if(GfxBase = OpenLibrary("graphics.library",37))
  305.                 {
  306.                     /* Now do the real work */
  307.                     NewList(&mylist);
  308.                     if(fillList("sys:"))
  309.                     {
  310.                         sortList();
  311.                         setupWindow();
  312.                     }
  313.                     freeList();
  314.                     CloseLibrary(GfxBase);
  315.                 }
  316.                 else
  317.                     printf("Error: could not open graphics.library\n");
  318.                 CloseLibrary(DosBase);
  319.             }
  320.             else
  321.                 printf("Error: could not open dos.library\n");
  322.             CloseLibrary(GadToolsBase);
  323.         }
  324.         else
  325.             printf("Error: could not open gadtools.library\n");
  326.         CloseLibrary(IntuitionBase);
  327.     }
  328.     else
  329.         printf("Error: could not open intuition.library\n");
  330. }
  331.  
  332. /* Setup the window -- do the GadTools stuff */
  333. void setupWindow()
  334. {
  335.     struct Screen* scr;
  336.     /* We'll copy the visual information for the default public screen */
  337.   /* (usually, this is the Workbench screen) */
  338.     if(scr = LockPubScreen(NULL))
  339.     {
  340.         APTR vinfo;
  341.         /* Get the visual info so GadTools can render the gadgets nicely */
  342.         if(vinfo = GetVisualInfo(scr, TAG_DONE))
  343.         {
  344.             struct Gadget* glist = NULL;
  345.             struct Gadget* listgad;
  346.             if(listgad = CreateContext(&glist))
  347.             {
  348.                 struct NewGadget newgad;
  349.                 /* The offsets of our window borders */
  350.                 int offleft = scr->WBorLeft;
  351.                 int offtop = scr->WBorTop + (scr->Font->ta_YSize + 1);
  352.                 struct Hook renderHook;
  353.                 renderHook.h_Entry = (HOOKFUNC)RenderHook;
  354.                 /* Setup our first gadget */
  355.                 newgad.ng_TextAttr         = &topazFont;
  356.                 newgad.ng_VisualInfo     = vinfo;
  357.                 newgad.ng_LeftEdge         = MYGAD_LEFT + offleft;
  358.                 newgad.ng_TopEdge         = MYGAD_TOP + offtop;
  359.                 newgad.ng_Width             = MYGAD_WIDTH;
  360.                 newgad.ng_Height             = MYGAD_HEIGHT;
  361.                 newgad.ng_GadgetText    = MYGAD_TEXT;
  362.                 newgad.ng_GadgetID        = MYGAD_ID;
  363.                 newgad.ng_Flags                = 0;
  364.                 /* Now create it and add it to our list */
  365.                 if(listgad = CreateGadget(LISTVIEW_KIND, listgad, &newgad,
  366.                                                                     GTLV_Labels,        &mylist,
  367.                                                                     GTLV_CallBack,    &renderHook,
  368.                                                                     TAG_DONE))
  369.                     createWindow(glist);
  370.                 else
  371.                     printf("Error: could not create gadget(s)\n");
  372.                 /* Free the gadget */
  373.                 FreeGadgets(glist);
  374.             }
  375.             else
  376.                 printf("Error: could not create GadTools context\n");
  377.             FreeVisualInfo(vinfo);
  378.         }
  379.         else
  380.             printf("Error: could not get visual info\n");
  381.         UnlockPubScreen(NULL, scr);
  382.     }
  383.     else
  384.         printf("Error: could not lock public screen\n");
  385. }
  386.  
  387. /* Actually open the window, in the normal way */
  388. void createWindow(struct Gadget* glist)
  389. {
  390.     struct Window* win;
  391.     /* Open our window */
  392.     if(win = OpenWindowTags(NULL,
  393.                                                     WA_InnerWidth,    MYWIN_WIDTH,
  394.                                                     WA_InnerHeight,    MYWIN_HEIGHT,
  395.                                                     WA_Title,        "Directory List",
  396.                                                     WA_Flags,        WFLG_CLOSEGADGET | WFLG_DRAGBAR,
  397.                                                     WA_IDCMP,        IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | LISTVIEWIDCMP,
  398.                                                     WA_Gadgets,    glist,
  399.                                                     TAG_DONE,        0))
  400.     {
  401.         /* Let GadTools refresh its bits of the window */
  402.         GT_RefreshWindow(win, NULL);
  403.         /* Now handle messages */
  404.         handleIDCMP(win);
  405.         CloseWindow(win);
  406.     }
  407.     else
  408.         printf("Error: could not open window\n");
  409. }
  410.  
  411. /* Our message handling code */
  412. void handleIDCMP(struct Window* win)
  413. {
  414.     int going = TRUE;
  415.     while(going)
  416.     {
  417.         struct IntuiMessage* intuimsg;
  418.         /* Wait for messages to arrive */
  419.         WaitPort(win->UserPort);
  420.         /* Messages have arrived: loop through all of them */
  421.         while(intuimsg = GT_GetIMsg(win->UserPort))
  422.         {
  423.             /* Act on this message... */
  424.             switch(intuimsg->Class)
  425.             {
  426.             case IDCMP_CLOSEWINDOW:
  427.                 going = FALSE;
  428.                 break;
  429.             case IDCMP_REFRESHWINDOW:
  430.                 /* You *MUST* remember to ask for and handle these refresh messages */
  431.                 GT_BeginRefresh(win);
  432.                 GT_EndRefresh(win, TRUE);
  433.                 break;
  434.             }
  435.             /* Reply when finished with message */
  436.             GT_ReplyIMsg(intuimsg);
  437.         }
  438.     }
  439. }
  440.  
  441.